//
// Created by 朕与将军解战袍 on 2022/3/13.
//

#ifndef TRUETYPERENDER_TTF_INFO_H
#define TRUETYPERENDER_TTF_INFO_H

// TODO 解析一个 glyph

// TODO 删除
#define TTF_RENDER_IMPLEMENT

#include "ttf_tables.h"
#include "ttf_setup.h"

/**
 * 用于读取 ttf 数据 (大端序)
 */
void ttfRead(
    IN const void *src,
    OUT void *des,
    IN uintptr_t size
);
#define TTF_READ(SRC, OFFSET, DES) \
ttfRead((SRC)+(OFFSET), &(DES), sizeof(DES))

#define TTF_UINT16_SWAP_BYTE(NUM) ((uint16_t)((uint16_t)(NUM) << 8 | (uint16_t)(NUM) >> 8))

/**
 * 适用前提: sizeof(a) == sizeof(b)
 * @return -1: a <  b <br>
 *          0: a == b <br>
 *          1: a >  b
 */
int compareUintBigEndian(
    IN void*  a_big_endian_ptr,
    IN void*  b_big_endian_ptr,
    IN size_t size
);
/**
 * 适用前提: sizeof(a) == sizeof(b)
 */
#define TTF_COM_UINT(UINT_A, UINT_B) compareUintBigEndian(&(UINT_A), &(UINT_B), sizeof(UINT_A))

/**
 * 二分查找下界
 * @param nums 非降序数组(大端序)
 * @param target 搜索目标(大端序)
 * @param len 数组长度
 * @return 返回 nums 中第一个小于或等于 target 的数的下标, 若不存在则返回 -1
 */
int lowerBoundBigEndian(
    IN uint16_t *nums,
    IN uint16_t  target,
    IN int       len
);

/**
 * 二分查找上界
 * @param nums 非降序数组(大端序)
 * @param target 搜索目标(大端序)
 * @param len 数组长度
 * @return 返回 nums 中第一个大于或等于 target 的数的下标, 若不存在则返回 -1
 */
__attribute__((unused)) int upperBoundBigEndian(
    IN uint16_t *nums,
    IN uint16_t  target,
    IN int       len
);

/**
 * 代表 ttf 文件
 * 可以通过 TTFInfo 得到其它的表 / 表的 info
 */
typedef struct ttf_info {
    void *ttfData;
    OffsetSubtable offsetSubtable;
    TableDir cacheTableDir;
    size_t rc;
} TTFInfo;

/**
 * 初始化 ttfInfo
 * @param ttfData ttf 文件数据
 * @error UNSUPPORTED_TTF_FORMAT
 */
TTFStatus initTTFInfo(
    IN  void *ttfData,
    OUT TTFInfo   *ttfInfo
);
#define UNSUPPORTED_TTF_FORMAT ((TTFStatus)0xfe)

/**
 * 释放 ttfInfo 内存
 */
TTFStatus freeTTFInfo(
    IN TTFInfo *ttfInfo
);
#define RC_NON_ZERO ((TTFStatus)0xfd)

/**
 * 用于释放通过 ttfInfo 中创建 info <br>
 * 未定义行为: 重复释放
 */
TTFStatus freeCreatedInfo(
    IN void *createdInfo
);

/**
 * 将 ttfInfo 指向第 N 个 TableDir
 * @error OUT_OF_BOUNDARY: 超出范围
 */
TTFStatus moveToNThTableDir(
    IN TTFInfo *ttfInfo,
    IN size_t  n
);

/**
 * 将 ttfInfo 指向 tag 指定的表
 * @error TABLE_NOT_FOUND: 找不到 tag 指定的表
 */
TTFStatus moveToSpecificTableDir(
    IN TTFInfo  *ttfInfo,
    IN uint32_t tag
);
#define TABLE_NOT_FOUND ((TTFStatus)0xfc)

/**
 * 将 ttfInfo 指向 headTable, 并将其读出
 * @error TABLE_NOT_FOUND: 找不到 headTable <br>
 *        INVALID_PARAMETER: headTable 的魔数和标准定义不一致, 可能是数据损坏
 */
TTFStatus getHeadTable(
    IN  TTFInfo   *ttfInfo,
    OUT HeadTable *headTable
);

/**
 * 将 ttfInfo 指向 maxpTable, 并将其读出
 * @error TABLE_NOT_FOUND: 找不到 maxpTable <br>
 *        INVALID_PARAMETER: maxpTable 的 version 不为 1.0, 可能是数据损坏?(现在还不清楚是否只有一个版本)
 */
TTFStatus getMaxpTable(
    IN  TTFInfo   *ttfInfo,
    OUT MaxpTable *maxpTable
);

/**
 * 用于表示所以 ttf cmap table 的信息
 * 可用用于寻找特定的 cmap table
 */
typedef struct ttf_cmap_info {
    TTFInfo *ttfInfo;
    void *ttfData;
    uint16_t numsTables;
    CmapSubTable cacheSubTable;
} CmapInfo;

/**
 * 用于表示 cmap 的信息
 * 用于以某种格式(CMAP_FORMAT_XX), 读取某个 cmapSubtable
 */
typedef struct ttf_cmap_format_4_info {
    TTFInfo *ttfInfo;
    CmapFormat4 format4Table;
} CmapFormat4Info;

/**
 * 通过 ttf info 获得 camp table info,
 * 会将 ttfInfo 指向 cmap table 对应的 table dir
 * @error TABLE_NOT_FOUND: 找不到 CMAP <br>
 *        UNSUPPORTED_VERSION: 不支持的 CMAP 版本
 */
TTFStatus getCmapInfo(
    IN  TTFInfo  *ttfInfo,
    OUT CmapInfo *cmapInfo
);
#define UNSUPPORTED_VERSION ((TTFStatus)0xfb)

/**
 * 将 cmapInfo 指向第 N 个 cmapSubtable
 * @error OUT_OF_BOUNDARY: 超出范围
 */
TTFStatus moveToNthCmapSubTable(
    IN CmapInfo *cmapInfo,
    IN size_t    n
);

/**
 * 获取 cmapInfo 现在指向的 cmapSubtable 的格式
 * @return 格式编号, 对应 CMAP_FORMAT_XX 系列宏
 */
uint16_t getCmapSubTableFormat(
    IN CmapInfo *cmapInfo
);

/**
 * 将 cmapInfo 现在指向的 cmapSubtable 以 format 4(CMAP_FORMAT_4) 读出
 * @error FORMAT_MISMATCHED: 现在指向的 cmapSubtable 的格式并不是 format 4
 */
TTFStatus cmapReadAsFormat4(
    IN  CmapInfo        *cmapInfo,
    OUT CmapFormat4Info *format4Info
);
#define FORMAT_MISMATCHED ((TTFStatus)0xfa)

/**
 * 在 format 4 中搜索 c 对应的 glyphIndex
 * @error MISSING_CHAR_GLYPH: 缺失 c 对应的 glyph
 */
TTFStatus format4SearchGlyphIndex(
    IN  CmapFormat4Info *format4Info,
    IN  wchar_t          c,
    OUT uint16_t        *glyphIndex
);
#define MISSING_CHAR_GLYPH ((TTFStatus)0xf9)

typedef struct ttf_loca_info {
    TTFInfo  *ttfInfo;
    int16_t   locaType;
    void     *locaData;
} LocaInfo;

/**
 * 通过 ttf info 获得 loca table info,
 * 会将 ttfInfo 指向 loca table 对应的 table dir
 * @error TABLE_NOT_FOUND: 找不到 loca table <br>
 *        INVALID_PARAMETER: 错误的 locaType
 */
TTFStatus getLocaInfo(
    IN  TTFInfo  *ttfInfo,
    OUT LocaInfo *locaInfo,
    IN  int16_t   locaType
);

/**
 * 通过 glyphIndex 在 loca table 中查询得到的结果
 */
typedef struct glyph_location {
    uint32_t offset; // 相对于 glfy table 头的偏移量
    uint32_t length; // 数据长度(以 byte 为单位)
} GlyphLocation;

/**
 * 通过 glyphIndex 在 loca table 中查询对应的 glyphLocation
 * @error INVALID_PARAMETER: 错误的 locaType,
 * 请确保 locaInfo 通过 getLocaInfo 创建
 */
TTFStatus getGlyphLocation(
    IN  LocaInfo      *locaInfo,
    IN  uint16_t       glyphIndex,
    OUT GlyphLocation *glyphLocation
);

#endif //TRUETYPERENDER_TTF_INFO_H
